#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Create by zhang
# Create on 2023-03-02 19:19
from __future__ import annotations

import datetime
import threading
from dataclasses import dataclass
from enum import Enum
from typing import Any, Dict, List

from core.enums import StockTradeDataType, TradeType, EventType, ResultCode, Period, DateFormat, TradeStatus
from core import logger


@dataclass
class StockDataDownloadConfiguration:
    """
    股票交易数据下载配置类
    """
    security: str
    """证券"""
    dataType: StockTradeDataType = StockTradeDataType.daily
    """数据类型"""


class StockTradeDataColumnName(Enum):
    STOCK_CODE = 'ts_code'
    """股票代码"""
    STOCK_CODE_FULL = 'ts_code_full'
    """股票代码带交易所标志"""
    NAME = 'name'
    """股票代码"""
    DATE_INDEX = 'date_index'
    """日期索引"""
    TRADE_DATE = 'trade_date'
    """
    交易日期： 格式为%Y%m%d或%Y%m%d%H%M%S
    """
    OPEN = 'open'
    """开盘价"""
    HIGH = 'high'
    """最高价"""
    LOW = 'low'
    """最低价"""
    CLOSE = 'close'
    """收盘价"""
    PRE_CLOSE = 'pre_close'
    """昨收价"""
    AFTER_CLOSE = 'after_close'
    """明天收盘价"""
    CHANGE = 'change'
    """涨跌额"""
    PCT_CHG = 'pct_chg'
    """涨跌幅"""
    VOL = 'vol'
    """成交量 （手）"""
    AMOUNT = 'amount'
    """成交额 （千元）"""
    TURNOVER_RATE = 'turnover_rate'
    """
    换手率
        也称做周转率，是指在一定的时间内市场中股票转手买卖的频率，是反映股票流通性强弱的一个指标。
        公式为：周转率(换手率)=(某一段时期内的成交量)/(发行总股数)x100%
    """
    STOCK_AMPLITUDE = 'stock_amplitude'
    """
    振幅
        股票开盘后的当日最高价和最低价之间的差的绝对值与前日收盘价的百分比，它在一定程度上表现股票的活跃程度。
    """


class TradeInfo:
    def __init__(self):
        self.lot: int = 0
        """手数"""
        self.price: float = 0.0
        """"下单单股价钱"""
        self.security: str = None
        """股票代码"""
        self.tradeType: TradeType = None
        """"下单类型"""
        self.time: datetime.datetime = None
        """记录产生时间"""
        self.status: TradeStatus = None
        """"状态"""
        self.remark: str = None
        """"备注"""
        self.remainLot: int = None
        """"备注"""
        self.total: float = None
        """"总额"""
        self.fees: float = None
        """"总费"""
        self.profit: float = None
        """"盈利"""

    def setLot(self, lot: int):
        self.lot = lot
        if self.tradeType is not None and self.tradeType == TradeType.BUY:
            self.remainLot = lot
        return self

    def setPrice(self, price: float):
        self.price = price
        return self

    def setSecurity(self, security: str):
        self.security = security
        return self

    def setTradeType(self, tradeType: TradeType):
        self.tradeType = tradeType
        if self.tradeType == TradeType.BUY and self.lot > 0:
            self.remainLot = self.lot
        return self

    def setTime(self, time: datetime.datetime):
        self.time = time
        return self

    def setStatus(self, status: TradeStatus):
        self.status = status
        return self

    def setRemark(self, remark: str):
        self.remark = remark
        return self

    def setTotal(self, total: float):
        self.total = total
        return self

    def setFees(self, fees: float):
        self.fees = fees
        return self

    def setProfit(self, profit: float):
        self.profit = profit
        return self

    def __str__(self):
        return f"tradeType={self.tradeType.name}, security={self.security}, price={str(self.price)}, lot={str(self.lot * 100)}, time={self.time.strftime(DateFormat.Y_m_d_H_M_S.value)}"


class R:
    def __init__(self, code: ResultCode=ResultCode.SUCESS, msg: str = "sucess", data: Any = None):
        self.code: ResultCode = code
        self.msg: str = msg
        self.data: Any = data

    @classmethod
    def sucess(cls, data: Any = None, msg:str="sucess"):
        return cls(ResultCode.SUCESS, msg, data)

    @classmethod
    def fail(cls, msg:str="fail", data: Any = None):
        return cls(ResultCode.FAIL, msg, data)

    @classmethod
    def error(cls, msg:str="error", data: Any = None):
        return cls(ResultCode.ERROR, msg, data)

    def setMsg(self, msg:str):
        self.msg = msg
        return self

    def setCode(self, code: ResultCode):
        self.code = code
        return self

    def setData(self, data: Any = None):
        self.data = data
        return self

    def __str__(self):
        s = f"code={self.code}; msg={self.msg};"
        if self.data is not None:
            s = s + f"; data={str(self.data)}"
        return s


class Event:
    """事件对象"""
    _priority_dict = {
        EventType.TIP_COMMON.name: 0,
        EventType.TIP_LOW.name: 0,
        EventType.TIP_HIGH.name: 9000,

        EventType.TRADE_BUY.name: 9999,
        EventType.TRADE_SELL.name: 9999,

        EventType.DATA_DOWNLOAD.name: 9000,
        EventType.DATA_DOWNLOAD.name: 9000,

        EventType.TIMER_UPDATED.name: 9000,
        EventType.TIME_UPDATED.name: 9000,

        EventType.TACTIC_MONITOR.name: 9000,
        EventType.TACTIC_UNMONITOR.name: 9000,
        EventType.TACTIC_INIT.name: 0,
    }

    def __init__(self, type: EventType, data: R):
        self.type: EventType = None
        """事件类型"""
        self.data: R = data
        """字典用于保存具体的事件数据"""
        self.order: int = 0
        self.setType(type)

    def setType(self, type: EventType):
        self.type = type
        self.order = self._priority_dict[type.name]

    def __lt__(self, other: Event):
        return self.order < other.order

    def __str__(self):
        return f"EventType={str(self.type)}, data={str(self.data)}"


class TacticResultData:
    def __init__(self):
        self.eventType: EventType = None
        self.security: str = None
        """股票代码"""
        self.dt: datetime.datetime = None
        """策略选择的时间"""
        self.opdt: datetime.datetime = None
        """下次操作基准时间"""
        self.period: Period = None
        """策略使用的周期"""
        self.isInRealtime: bool = True
        """是否是实时"""
        self.price: float = 0
        """策略选择时的价格"""
        self.classify: str = None
        """对于多线程多进程共享存储中的键"""
        self.sourceClassify: str = None
        """对于多线程多进程共享存储中的键"""
        self.original: TacticResultData = None
        """原始的策略结果"""

    def setEventType(self, eventType: EventType):
        self.eventType = eventType
        return self

    def setSecurity(self, security: str):
        self.security = security
        return self

    def setDt(self, dt: datetime.datetime):
        self.dt = dt
        self.opdt = dt
        return self

    def setOpdt(self, opdt: datetime.datetime):
        self.opdt = opdt
        return self

    def setPeriod(self, period: Period):
        self.period = period
        return self

    def setIsInRealtime(self, isInRealtime: bool):
        self.isInRealtime = isInRealtime
        return self

    def setPrice(self, price: float):
        self.price = price
        return self

    def setClassify(self, classify: str):
        self.classify = classify
        return self

    def setSourceClassify(self, sourceClassify: str):
        self.sourceClassify = sourceClassify
        return self

    def setOriginal(self, original: TacticResultData):
        self.original = original
        return self

    def __str__(self):
        s = f"eventType={self.eventType.name}, security={self.security}"
        if self.period is not None:
            s = s + f", period={self.period.name}"
        if self.price > 0:
            s = s + f", price={str(self.price)}"
        s = s + f", isInRealtime={str(self.isInRealtime)}"
        if self.dt is not None:
            s = s + f" ,dt={self.dt.strftime(DateFormat.Y_m_d_H_M_S.value)},"
        if self.opdt is not None:
            s = s + f" ,opdt={self.opdt.strftime(DateFormat.Y_m_d_H_M_S.value)},"
        if self.original is not None:
            s = s + f"\n\toriginal=[{str(self.original)}]"
        return s


class SecurityHolder:
    def __init__(self):
        self.infoDict: Dict[str, TacticResultData] = {}
        self.ins: List[str] = []
        self.outs: List[str] = []
        self.lock: threading.Lock = None

    def setLock(self, lock: threading.Lock):
        self.lock = lock
        return self

    def getInfo(self, security: str) -> TacticResultData:
        if security is not None and security in self.infoDict:
            return self.infoDict[security]
        return None

    def setInfo(self, data: TacticResultData) -> TacticResultData:
        self.infoDict[data.security] = data
        return self

    def getInfoByInsIndex(self, index: int) -> TacticResultData:
        if self.lock is not None:
            with self.lock:
                return self.infoDict[self.ins[index]]
        else:
            return self.infoDict[self.ins[index]]

    def addSecurity(self, data: TacticResultData) -> SecurityHolder:
        if data.security in self.ins:
            return self
        elif data.security in self.outs:
            self.outs = [s for s in self.outs if s != data.security]
            self.ins = [data.security] + self.ins
            self.infoDict[data.security] = data
        else:
            self.ins = [data.security] + self.ins
            self.infoDict[data.security] = data
        return self

    def addSecurities(self, securities: List[str], dt: datetime.datetime = None) -> SecurityHolder:
        if dt is None:
            dt = datetime.datetime.now()
        if securities is None or len(securities) == 0:
            return self
        for s in securities:
            d = TacticResultData().setEventType(EventType.TACTIC_INIT).setSecurity(s).setDt(dt)
            self.addSecurity(d)
        return self

    def delSecurity(self, data: TacticResultData) -> SecurityHolder:
        if data.security in self.ins:
            self.outs = [data.security] + self.outs
            self.ins = [s for s in self.ins if s != data.security]
            # data.original = self.infoDict[data.security]
            self.infoDict[data.security] = data
        return self

    def __str__(self):
        s =     "\tIN        :" + ",".join([s[:-3] for s in self.ins])
        s = s + "\n"
        s = s + "\tIN  Detail:\n\t\t" + "\n\t\t".join([f'{s[:-3]}[{self.infoDict[s]}]' for s in self.ins])
        s = s + "\n"
        s = s + "\tOUT Detail:\n\t\t" + "\n\t\t".join([f'{s[:-3]}[{self.infoDict[s]}]' for s in self.outs])
        return s


class SecurityGetter:

    def __init__(self, shareDict: Dict[str, SecurityHolder], key: str):
        self.shareDict: Dict[str, SecurityHolder] = shareDict
        self.key: str = key

    def __call__(self) -> TacticResultData:
        l = len(self.shareDict[self.key].ins)
        for i in range(l):
            r = self.shareDict[self.key].getInfoByInsIndex(i)
            logger.info(f"总共{l}只股票，当前是第{i}只: {r.security}")
            yield r
